#pragma once
#include "Headerfile.hpp"
#include "Sink.hpp"
#include "Level.hpp"
#include "Message.hpp"
#include "Formatter.hpp"
#include "Looper.hpp"
#include "buffer.hpp"
namespace shw
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::vector<shw::SinkLog::ptr> &sink,
               shw::Format::ptr format,
               const std::string &name,
               level::value limitLevel = level::value::DEBUG)
            : _sink(sink.begin(), sink.end()), _limitLevel(limitLevel), _format(format), _loggerName(name)
        {
        }
        virtual ~Logger() {}
        const std::string& Getname()//获取日志器名称，用const引用防止外界修改
        {
            return _loggerName;
        }

        virtual void Log(const char *data, size_t len) = 0;
        void Debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (ShouldSink(level::value::DEBUG) == 0)
                return;
            // 先把变参拿到
            va_list va;
            char *buf;
            va_start(va, fmt);
            assert(vasprintf(&buf, fmt.c_str(), va)); // 可变参数拿到失败直接退出
            va_end(va);
            shw::message msg(line, _loggerName, file, std::string(buf), level::value::DEBUG);
            auto str = _format->format(msg);
            Log(str.c_str(), str.size()); // 落地输出
            free(buf);                    // vasprintf会动态申请空间赋值给buf，需要释放
        }
        void Info(const std::string &file, size_t line, const std::string &fmt, ...)
        {

            if (ShouldSink(level::value::INFO) == 0)
                return;
            // 先把变参拿到
            va_list va;
            char *buf;
            va_start(va, fmt);
            assert(vasprintf(&buf, fmt.c_str(), va)); // 可变参数拿到失败直接退出
            va_end(va);
            shw::message msg(line, _loggerName, file, std::string(buf), level::value::INFO);
            auto str = _format->format(msg);
            Log(str.c_str(), str.size()); // 落地输出
            free(buf);                    // vasprintf会动态申请空间赋值给buf，需要释放
        }
        void Warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (ShouldSink(level::value::WARN) == 0)
                return;
            // 先把变参拿到
            va_list va;
            char *buf;
            va_start(va, fmt);
            assert(vasprintf(&buf, fmt.c_str(), va)); // 可变参数拿到失败直接退出
            va_end(va);
            shw::message msg(line, _loggerName, file, std::string(buf), level::value::WARN);
            auto str = _format->format(msg);
            Log(str.c_str(), str.size()); // 落地输出

            free(buf); // vasprintf会动态申请空间赋值给buf，需要释放
        }
        void Error(const std::string &file, size_t line, const std::string &fmt, ...)
        {

            if (ShouldSink(level::value::ERROR) == 0)
                return;
            // 先把变参拿到
            va_list va;
            char *buf;
            va_start(va, fmt);
            assert(vasprintf(&buf, fmt.c_str(), va)); // 可变参数拿到失败直接退出
            va_end(va);
            shw::message msg(line, _loggerName, file, std::string(buf), level::value::ERROR);
            auto str = _format->format(msg);
            Log(str.c_str(), str.size()); // 落地输出

            free(buf); // vasprintf会动态申请空间赋值给buf，需要释放
        }
        void Fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (ShouldSink(level::value::FATAL) == 0)
                return;

            // 先把变参拿到
            va_list va;
            char *buf;
            va_start(va, fmt);
            assert(vasprintf(&buf, fmt.c_str(), va)); // 可变参数拿到失败直接退出
            va_end(va);
            shw::message msg(line, _loggerName, file, std::string(buf), level::value::FATAL);
            auto str = _format->format(msg);
            Log(str.c_str(), str.size()); // 落地输出

            free(buf); // vasprintf会动态申请空间赋值给buf，需要释放
        }

    protected:
        bool ShouldSink(level::value level)
        {
            return level >= _limitLevel;
        } // 控制输出等级，级别大可以输出
    protected:
        std::mutex _mutex;
        std::vector<shw::SinkLog::ptr> _sink;       // 同一个文件可能有多个落地方向
        std::atomic<shw::level::value> _limitLevel; // 控制输出级别
        shw::Format::ptr _format;
        std::string _loggerName; // 日志器名称
    };
    class SynchronousLogger : public Logger
    {
    public:
        SynchronousLogger(const std::vector<shw::SinkLog::ptr> &sink,
                          shw::Format::ptr format,
                          const std::string &name,
                          level::value limitLevel = level::value::DEBUG)
            : Logger(sink, format, name, limitLevel)
        {
        }
        void Log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sink.empty())
                return; // 如果为空直接退出
            for (auto &it : _sink)
            {
                it->Log(data, len);
            }
        }
    };
    class ASynchronousLogger : public Logger
    {
    public:
        ASynchronousLogger(const std::vector<shw::SinkLog::ptr> &sink,
                           shw::Format::ptr format,
                           const std::string &name,
                           AsyncLooperType type,
                           level::value limitLevel = level::value::DEBUG)
            : Logger(sink, format, name, limitLevel), _Asyloop(std::make_shared<AsyncLooper>(std::bind(&ASynchronousLogger::RealLog, this, std::placeholders::_1), type))
        {
        }
        void Log(const char *data, size_t len) override
        {
            _Asyloop->Push(data);
        }
        void RealLog(Buffer &buf)
        {
            size_t count = 0;
            if (_sink.empty())
                return; // 如果为空直接退出
            for (auto &it : _sink)
            {
                it->Log(buf.Begin(), buf.ReadAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _Asyloop; // 异步工作器
    };
    enum class LoggerType
    {
        LOGGER_SYNC = 0, // 同步日志器
        LOGGER_ASYNC     // 异步日志器
    };

    class LoggerBuilder
    {
    public:
        LoggerBuilder()
            : _typeLogger(LoggerType::LOGGER_SYNC), _limitLevel(level::value::DEBUG), _typeAsyncLooper(shw::AsyncLooperType::AsyncLooper_SAFE)
        {
        }
        void EnableUnsafeAsyncLooperbuilder()
        {
            _typeAsyncLooper = AsyncLooperType::AsyncLooper_UNSAFE;
        }
        void Levelbuilder(shw::level::value limitLevel) { _limitLevel = limitLevel; }
        void Formatbuilder(const std::string &parten) { _format = std::make_shared<shw::Format>(parten); }
        void Namebuilder(const std::string loggerName) { _loggerName = loggerName; }
        void LoggerTypebuilder(shw::LoggerType typeLogger) { _typeLogger = typeLogger; }
        template <typename SinkType, typename... Args>
        void Sinkbuilder(Args &&...args)
        {
            shw::SinkLog::ptr psink = shw::SinkFactory::CreateSink<SinkType>(std::forward<Args>(args)...);
            _sink.push_back(psink);
        }
        virtual Logger::ptr Builder() = 0;
    protected:
        shw::AsyncLooperType _typeAsyncLooper; // 日志器安全模式，默认是安全模式
        shw::LoggerType _typeLogger;
        std::mutex _mutex;
        std::vector<shw::SinkLog::ptr> _sink; // 同一个文件可能有多个落地方向
        shw::level::value _limitLevel;        // 控制输出级别
        shw::Format::ptr _format;
        std::string _loggerName; // 日志器名称
    };
    class LocalLoggerBuilder : public LoggerBuilder//本地日志建造者
    {
    public:
        using ptr=std::shared_ptr<LocalLoggerBuilder>;
        LocalLoggerBuilder() {}
        Logger::ptr Builder() override
        {
            assert(!_loggerName.empty()); // 必须得有日志器名称
            if (_format.get() == nullptr)
            {
                _format = std::make_shared<shw::Format>();
            }
            if (_sink.empty()) // 如果落地方向为空，添加默认标准输出
            {
                Sinkbuilder<StoutSink>();
            }
            if (_typeLogger == LoggerType::LOGGER_SYNC)
            {
                return std::make_shared<SynchronousLogger>(_sink, _format, _loggerName);
            }
            else
            {
                return std::make_shared<ASynchronousLogger>(_sink, _format, _loggerName, _typeAsyncLooper);
            }
        }
    };
    class LoggerManager//日志器管理
    {
        //1.懒汉单例模式，提供全局访问
        //2.默认日志器，提供简单使用（构造时应该创建好本地）
        //成员函数
        //a.添加功能
        //b.按照日志器名称查找功能
        //c.获取单例
        
        //数据成员
        //A.互斥锁，保证线程安全
        //B.容器：存放日志器，unorder_map
        //C.默认日志器
    public:
        static LoggerManager& GetInstanceLogM()
        {
            static LoggerManager logM;
            return logM;
        }
        void AddLogger(std::string name, shw::Logger::ptr logger)
        {
            std::unique_lock<std::mutex>lock(_mutex);//加锁保护线程安全
            _loggerManager.insert(std::make_pair(name,logger));
        }
        //查找日志器,返回迭代器
        bool FindLogger(const std::string& name)
        {
            auto retLogger=_loggerManager.find(name);
            if(retLogger==_loggerManager.end())
            {
                return false;
            }
            return true;
        }
        const Logger::ptr& GetRootlogger(){return _rootLogger;}
        const Logger::ptr Getlogger(const std::string&name)
        {
            auto retLogger=_loggerManager.find(name);
            if(retLogger==_loggerManager.end())
            {
                return nullptr;//找不到返回临时匿名对象
            }
            return (*retLogger).second;
            
        }
    private:
        LoggerManager()//创建默认本地日志器
        {
            std::unique_ptr<shw::LocalLoggerBuilder> LLB(new shw::LocalLoggerBuilder());
            LLB->Namebuilder("_root");
            _rootLogger=LLB->Builder();
            AddLogger(_rootLogger->Getname(),_rootLogger);
        }
    private:
        shw::Logger::ptr _rootLogger;//默认日志器
        std::unordered_map<std::string,shw::Logger::ptr> _loggerManager;
        std::mutex _mutex;

    };
    
    class GlobalLoggerBuilder : public LoggerBuilder//全局日志建造者
    {
    public:
        using ptr=std::shared_ptr<GlobalLoggerBuilder>;
        GlobalLoggerBuilder() {}
        Logger::ptr Builder() override
        {
            assert(!_loggerName.empty()); // 必须得有日志器名称
            if (_format.get() == nullptr)
            {
                _format = std::make_shared<shw::Format>();
            }
            if (_sink.empty()) // 如果落地方向为空，添加默认标准输出
            {
                Sinkbuilder<StoutSink>();
            }
            Logger::ptr retPtr;
            if (_typeLogger == LoggerType::LOGGER_SYNC)
            {
                retPtr=std::make_shared<SynchronousLogger>(_sink, _format, _loggerName);
            }
            else
            {
                retPtr= std::make_shared<ASynchronousLogger>(_sink, _format, _loggerName, _typeAsyncLooper);
            }
            shw::LoggerManager::GetInstanceLogM().AddLogger(retPtr->Getname(),retPtr);
            return retPtr;
        }

    };
}